package com.tangsm.spring.boot.filter.common.wrapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;

/**
 * 包装HttpServletRequest，目的是让其输入流可重复读
 * <p>注：Json请求没问题，form-data请求可能出现参数丢失问题，尚未找到原因</p>
 *
 * @author tangsm
 **/
public class RequestWrapper extends HttpServletRequestWrapper {
    private static final Logger log = LoggerFactory.getLogger(RequestWrapper.class);

    /**
     * 缓冲区大小
     */
    private static final int BUFFER_SIZE = 1024;

    /**
     * 存储body数据的容器
     */
    private final byte[] body;

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);

        // 将body数据存储起来
        body = getBody(request).getBytes(Charset.defaultCharset());
    }

    /**
     * 获取请求Body
     *
     * @param request request
     * @return String
     */
    public String getBody(final ServletRequest request) throws IOException {
        return convertToStr(request.getInputStream());
    }

    /**
     * 获取请求Body
     *
     * @return String
     */
    public String getBody() {
        return convertToStr(new ByteArrayInputStream(body));
    }

    /**
     * InputStream转换成字符串
     * @param in 输入字节流
     * @return 字符串
     */
    public static String convertToStr(InputStream in) {
        if (in == null) {
            return "";
        }

        ByteArrayOutputStream os =  new ByteArrayOutputStream();
        try {
            byte[] buffer = new byte[BUFFER_SIZE];
            int len;
            while ((len = in.read(buffer)) > -1) {
                os.write(buffer, 0, len);
            }
            return os.toString();
        } catch (IOException e) {
            log.error("InputStream转换成字符串异常", e);
            return "";
        } finally {
            try {
                os.close();
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);

        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return inputStream.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }
}
